package com.xlib.util.so 
{
	import flash.display.Sprite;
	import flash.external.ExternalInterface;
	import flash.net.SharedObject;
	
	public class Storage extends Sprite
	{
		private const SO_KEY:String = "so_xlib";
		private var _so:SharedObject = null;
		private var _path:String = null;
		private var _secure:Boolean = false;
			
		public function Storage()
		{
			var param:Object = stage.loaderInfo.parameters;
			this._path = param.localPath || null;
			this._secure = ("1" == param.secure ? true : false);
			this.initShareObject();
			
			if (ExternalInterface.available)
			{
				ExternalInterface.addCallback("setItem", this.setItem);
				ExternalInterface.addCallback("getItem", this.getItem);
				ExternalInterface.addCallback("removeItem", this.removeItem);
				ExternalInterface.addCallback("clear", this.clear);
				ExternalInterface.addCallback("getSize", this.getSize);
				ExternalInterface.addCallback("getLocalPath", this.getLocalPath);
				ExternalInterface.addCallback("isSecure", this.isSecure);			
				ExternalInterface.call("XLib.SO.fireReady", true);
			}
		}
		
		private function initShareObject():void
		{
			this._so = SharedObject.getLocal(this.SO_KEY, this._path, this._secure);			
		}
		
		private function isExpired(expired:Number):Boolean
		{
			var date:Date = new Date();
			var ms:Number = date.getTime();
			return (expired <= ms);
		}
		
		private function calcExpired(expired:Number):Number
		{
			var date:Date = new Date();
			var ms:Number = date.getTime();
			var exp:Number = ms + expired;
			return exp;
		}
		
		public function setItem(key:String, value:* = null, expired:Number = 86400000):Boolean
		{
			try
			{
				var data:Object = this._so.data;
				var _expired:Number = (typeof(expired) == "number" ? expired : 86400000);
				data[key] = { "value":value, "expired":this.calcExpired(_expired) };
				this._so.flush(102400);
				return true;
			}
			catch (e:Error)
			{
				return false;
			}
			return false;
		}
		
		public function getItem(key:String):*
		{
			var data:Object = this._so.data;
			var item:Object = data[key];
			var value:* = null;
			var expired:Number = 0;
			if (null !== item)
			{
				expired = item["expired"];
				value = item["value"];
				if (true === this.isExpired(expired))
				{
					this.removeItem(key);
					value = null;
				}				
			}
			return value;
		}
		
		public function removeItem(key:String):Boolean
		{
			delete this._so.data[key];
			return (false === (key in this._so.data));
		}
		
		public function clear():void
		{
			this._so.clear();
		}
		
		private function clearExpiredData():void
		{
			var data:Object = this._so.data as Object;
			var item:Object = null;
			var expired:Number = 0;
			
			for (var key in data)
			{
				item = data[key];
				expired = item["expired"];
				if (true === this.isExpired(expired))
				{
					this.removeItem(key);
				}
			}
		}
		
		public function getSize():Number
		{
			this.clearExpiredData();
			return this._so.size;
		}
		
		public function getLocalPath():String
		{
			return this._path;
		}
		
		public function isSecure():Boolean
		{
			return this._secure;
		}
		
	}
}